/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>
#include <cstddef>
#include <cstdint>
#include <vector>
#include <memory>
#include <queue>
#include <string>
#undef private
#include "audio_info.h"
#include "hpae_inner_capturer_manager.h"
#include "i_hpae_renderer_manager.h"

using namespace std;
using namespace OHOS::AudioStandard::HPAE;


namespace OHOS {
namespace AudioStandard {
static const uint8_t *RAW_DATA = nullptr;
static size_t g_dataSize = 0;
static size_t g_pos;
const size_t THRESHOLD = 10;
typedef void (*TestPtr)(const uint8_t *, size_t);

template<class T>
T GetData()
{
    T object {};
    size_t objectSize = sizeof(object);
    if (RAW_DATA == nullptr || objectSize > g_dataSize - g_pos) {
        return object;
    }
    errno_t ret = memcpy_s(&object, objectSize, RAW_DATA + g_pos, objectSize);
    if (ret != EOK) {
        return {};
    }
    g_pos += objectSize;
    return object;
}

template<class T>
uint32_t GetArrLength(T& arr)
{
    if (arr == nullptr) {
        AUDIO_INFO_LOG("%{public}s: The array length is equal to 0", __func__);
        return 0;
    }
    return sizeof(arr) / sizeof(arr[0]);
}


void CreateStreamFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    const HpaeStreamInfo streamInfo = {};
    hpaeInnerCapturerManager->CreateStream(streamInfo);
}

void DestroyStreamFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->DestroyStream(sessionId);
}

void StartFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->Start(sessionId);
}

void PauseFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->Pause(sessionId);
}

void FlushFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->Flush(sessionId);
}

void DrainFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->Drain(sessionId);
}

void StopFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->Stop(sessionId);
}

void ReleaseFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->Release(sessionId);
}

void MoveStreamFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    const std::string &sinkName = "13222";
    hpaeInnerCapturerManager->MoveStream(sessionId, sinkName);
}

void MoveAllStreamFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    const std::vector<uint32_t> &sessionId = {GetData<uint32_t>(), GetData<uint32_t>(), GetData<uint32_t>()};
    const std::string &sinkName = "13222";
    hpaeInnerCapturerManager->MoveAllStream(sinkName, sessionId);
}

void SuspendStreamManagerFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    bool isSuspend = GetData<bool>();
    hpaeInnerCapturerManager->SuspendStreamManager(isSuspend);
}

void SetMuteFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    bool isMute = GetData<bool>();
    hpaeInnerCapturerManager->SetMute(isMute);
}

void ProcessFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->Process();
}

void HandleMsgFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->HandleMsg();
}

void InitFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->Init();
}

void DeInitFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->DeInit();
}

void IsInitFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->IsInit();
}

void IsRunningFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->IsRunning();
}

void IsMsgProcessingFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->IsMsgProcessing();
}

void DeactivateThreadFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->DeactivateThread();
}

void SetClientVolumeFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    float volume = GetData<float>();
    hpaeInnerCapturerManager->SetClientVolume(sessionId, volume);
}

void SetRateFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    int32_t rate = GetData<int32_t>();
    hpaeInnerCapturerManager->SetRate(sessionId, rate);
}

void SetAudioEffectModeFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    int32_t effectMode = GetData<int32_t>();
    hpaeInnerCapturerManager->SetAudioEffectMode(sessionId, effectMode);
}

void GetAudioEffectModeFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    int32_t e = GetData<int32_t>();
    int32_t &effectMode = e;
    hpaeInnerCapturerManager->GetAudioEffectMode(sessionId, effectMode);
}

void SetPrivacyTypeFuzzTest()

{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    int32_t privacyType = GetData<int32_t>();
    hpaeInnerCapturerManager->SetPrivacyType(sessionId, privacyType);
}

void GetPrivacyTypeFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    int32_t privacyType = GetData<int32_t>();
    hpaeInnerCapturerManager->GetPrivacyType(sessionId, privacyType);
}

void RegisterWriteCallbackFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    const std::weak_ptr<IStreamCallback> &callback = std::weak_ptr<IStreamCallback>();
    hpaeInnerCapturerManager->RegisterWriteCallback(sessionId, callback);
}

void GetWritableSizeFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->GetWritableSize(sessionId);
}

void UpdateSpatializationStateFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    hpaeInnerCapturerManager->UpdateSpatializationState(sessionId, true, true);
}

void UpdateMaxLengthFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    uint32_t maxLength = GetData<uint32_t>();
    hpaeInnerCapturerManager->UpdateMaxLength(sessionId, maxLength);
}

void GetAllSinkInputsInfoFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->GetAllSinkInputsInfo();
}

void GetSinkInputInfoFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    HpaeSinkInputInfo sinkInputInfo;
    hpaeInnerCapturerManager->GetSinkInputInfo(sessionId, sinkInputInfo);
}

void GetSinkInfoFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->GetSinkInfo();
}

void OnNodeStatusUpdateFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    IOperation operation = IOperation::OPERATION_INVALID;
    hpaeInnerCapturerManager->OnNodeStatusUpdate(sessionId, operation);
}

void OnFadeDoneFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    IOperation operation = IOperation::OPERATION_INVALID;
    hpaeInnerCapturerManager->OnFadeDone(sessionId, operation);
}

void AddNodeToSinkFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    HpaeNodeInfo nodeInfo;
    const std::shared_ptr<HpaeSinkInputNode> &node = std::make_shared<HpaeSinkInputNode>(nodeInfo);
    hpaeInnerCapturerManager->AddNodeToSink(node);
}

void AddAllNodesToSinkFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    std::vector<std::shared_ptr<HpaeSinkInputNode>> inputs;
    const std::vector<std::shared_ptr<HpaeSinkInputNode>> &sinkInputs = inputs;
    hpaeInnerCapturerManager->AddAllNodesToSink(sinkInputs, true);
}

void RegisterReadCallbackFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    const std::weak_ptr<ICapturerStreamCallback> &callback = std::weak_ptr<ICapturerStreamCallback>();
    hpaeInnerCapturerManager->RegisterReadCallback(sessionId, callback);
}

void GetSourceOutputInfoFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    uint32_t sessionId = GetData<uint32_t>();
    HpaeSourceOutputInfo sourceOutputInfo;
    hpaeInnerCapturerManager->GetSourceOutputInfo(sessionId, sourceOutputInfo);
}

void GetAllSourceOutputsInfoFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->GetAllSourceOutputsInfo();
}

void GetThreadNameFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->GetThreadName();
}

void ReloadRenderManagerFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->ReloadRenderManager(sinkInfo);
}

void GetDeviceHDFDumpInfoFuzzTest()
{
    HpaeSinkInfo sinkInfo;
    auto hpaeInnerCapturerManager = std::make_shared<HpaeInnerCapturerManager>(sinkInfo);
    hpaeInnerCapturerManager->GetDeviceHDFDumpInfo();
}

typedef void (*TestFuncs[43])();

TestFuncs g_testFuncs = {
    CreateStreamFuzzTest,
    DestroyStreamFuzzTest,
    StartFuzzTest,
    PauseFuzzTest,
    FlushFuzzTest,
    DrainFuzzTest,
    StopFuzzTest,
    ReleaseFuzzTest,
    MoveStreamFuzzTest,
    MoveAllStreamFuzzTest,
    SuspendStreamManagerFuzzTest,
    SetMuteFuzzTest,
    ProcessFuzzTest,
    HandleMsgFuzzTest,
    InitFuzzTest,
    DeInitFuzzTest,
    IsInitFuzzTest,
    IsRunningFuzzTest,
    IsMsgProcessingFuzzTest,
    DeactivateThreadFuzzTest,
    SetClientVolumeFuzzTest,
    SetRateFuzzTest,
    SetAudioEffectModeFuzzTest,
    GetAudioEffectModeFuzzTest,
    SetPrivacyTypeFuzzTest,
    GetPrivacyTypeFuzzTest,
    RegisterWriteCallbackFuzzTest,
    GetWritableSizeFuzzTest,
    UpdateSpatializationStateFuzzTest,
    UpdateMaxLengthFuzzTest,
    GetAllSinkInputsInfoFuzzTest,
    GetSinkInputInfoFuzzTest,
    GetSinkInfoFuzzTest,
    OnNodeStatusUpdateFuzzTest,
    OnFadeDoneFuzzTest,
    AddNodeToSinkFuzzTest,
    AddAllNodesToSinkFuzzTest,
    RegisterReadCallbackFuzzTest,
    GetSourceOutputInfoFuzzTest,
    GetAllSourceOutputsInfoFuzzTest,
    GetThreadNameFuzzTest,
    ReloadRenderManagerFuzzTest,
    GetDeviceHDFDumpInfoFuzzTest,
};

bool FuzzTest(const uint8_t *rawData, size_t size)
{
    if (rawData == nullptr) {
        return false;
    }

    // initialize data
    RAW_DATA = rawData;
    g_dataSize = size;
    g_pos = 0;

    uint32_t code = GetData<uint32_t>();
    uint32_t len = GetArrLength(g_testFuncs);
    if (len > 0) {
        g_testFuncs[code % len]();
    } else {
        AUDIO_INFO_LOG("%{public}s: The len length is equal to 0", __func__);
    }

    return true;
}

} // namespace AudioStandard
} // namespace OHOS

/* Fuzzer entry point */
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
    if (size < OHOS::AudioStandard::THRESHOLD) {
        return 0;
    }

    OHOS::AudioStandard::FuzzTest(data, size);
    return 0;
}